package pnu.ssm.ga;

public class GeneticAlgorithm {
	// GA parameters
	public static double uniformRate = 0.5;
	public static double mutationRate = 0.015;
	public static int tournamentSize = 5;
	public static boolean elitism = true;
	
	public static Population evolvePopulation(Population pop){
		Population newPopulation =  new Population(pop.size(), false);

		if(elitism) newPopulation.saveIndividual(0, pop.getFittestIndividual());
		
		int elitismOffset = elitism ? 1 : 0;
		
		for(int i=elitismOffset; i<pop.size(); i++){
			Individual indiv1 = tournamentSelection(pop); 
			Individual indiv2 = tournamentSelection(pop);
			Individual newIndiv = crossover(indiv1, indiv2);
			newPopulation.saveIndividual(i,newIndiv);
		}
		
		for(int i = elitismOffset; i<newPopulation.size(); i++)
			mutate(newPopulation.getIndividual(i));
		
		return newPopulation;
	}
	
	private static Individual crossover(Individual indiv1, Individual indiv2){
		Individual newSol = new Individual();
		newSol.initIndividual();
		for(int i=0; i<indiv1.size(); i++){
			if(Math.random() <= uniformRate){
				newSol.setGene(i, indiv1.getGene(i));
			} else {
				newSol.setGene(i, indiv2.getGene(i));
			}
		}
		return newSol;
	}
	
	private static void mutate (Individual indiv){
		for(int i=0; i<indiv.size(); i++){
			if(Math.random() <= mutationRate){
				int gene = (int) (Math.random() * Individual.getMaximumGeneNumber());
				indiv.setGene(i, gene);
			}
		}
	}
	
	private static Individual tournamentSelection(Population pop){
		Population tournament = new Population(tournamentSize, false);
		for(int i=0; i<tournamentSize; i++){
			int randomId = (int) (Math.random() * pop.size());
			tournament.saveIndividual(i, pop.getIndividual(randomId));
		}
		Individual fittest = tournament.getFittestIndividual();
		return fittest;
	}
}







